#include "../logs/log.h"
// #include <iostream>
// #include <fstream>
// #include "logmessage.hpp"
// #include "util.hpp"
// #include "level.hpp"
// #include "format.hpp"
// #include "sink.hpp"
// #include "logger.hpp"
// #include "buffer.hpp"
// #include <unistd.h>
// #include <memory>
// using namespace logs;
// int main()
// {
//     std::string path = "./aa/bb/cc/a.txt";
//     std::cout << util::Data::getTime() << std::endl;
//     util::File::createDirectory(util::File::getPath(path));

//     if(util::File::exists(path))
//         std::cout << "存在！" << std::endl;
//     else
//         std::cout << util::File::getPath(path) << std::endl;
//     return 0;
// }

// int main()
// {
//     std::cout << LogLevel::toString(LogLevel::Value::DEBUG) << std::endl;
//     std::cout << LogLevel::toString(LogLevel::Value::INFO) << std::endl;
//     std::cout << LogLevel::toString(LogLevel::Value::WARN) << std::endl;
//     std::cout << LogLevel::toString(LogLevel::Value::ERROR) << std::endl;
//     std::cout << LogLevel::toString(LogLevel::Value::FATAL) << std::endl;
//     std::cout << LogLevel::toString(LogLevel::Value::OFF) << std::endl;

//     return 0;
// }

// int main()
// {
//     logMsg lm(LogLevel::Value::DEBUG, __LINE__, __FILE__, "测试", "root");

//     return 0;
// }

// 错误日志：输出时没有打印[]: 原因：存储key、val字符串创建在了while循环中，导致每次读取到[]时（读取常规字符完毕时就会continue跳过此次循环）,每次进入循环就会导致key、val中数据清空
// int main()
// {
//     logMsg lm(LogLevel::Value::DEBUG, __LINE__, __FILE__, "格式化功能测试...", "root");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %n");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S] %m %n");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %n{");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %g");
//     Formatter fmt("abc%%%k%k%gdef[%d{%H:%M:%S}] %m %g");
//     // Formatter fmt;
//     std::string res = fmt.format(lm);
//     std::cout << res << std::endl;
//     return 0;
// }

enum class TimeGap
{
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY
};
// 进行扩展，一时间段来进行文件滚动
class RollByTimeSink : public logs::LogSink
{
public:
    RollByTimeSink(const std::string &base_name, TimeGap gap_type) : _file_name(base_name)
    {
        switch (gap_type)
        {
        case TimeGap::GAP_SECOND:
            _gap_size = 1;
            break;
        case TimeGap::GAP_MINUTE:
            _gap_size = 60;
            break;
        case TimeGap::GAP_HOUR:
            _gap_size = 3600;
            break;
        case TimeGap::GAP_DAY:
            _gap_size = 3600 * 24;
            break;
        }
        _cur_gap = logs::util::Data::getTime() / _gap_size;
        logs::util::File::createDirectory(logs::util::File::getPath(base_name));
        createNewFile();
    }
    void log(const char *data, size_t len)
    {
        // 判断是否在同一个时间段
        // 缺点就是，会创建多余文件；这样的问题也仅仅是在相对时间间隔较小的情况下出现，会多创建一个文件；（可忽略）
        // 调整：_cur_gap - logs::util::Data::getTime()计算第一次初始化创建文件到现在相差多少秒
        // 相差时间除以时间间隔，得到过了多少个时间间隔；
        if (logs::util::Data::getTime() / _gap_size != _cur_gap)
        {
            _ofs.close();
            createNewFile();
            _cur_gap = logs::util::Data::getTime() / _gap_size; // 注意更新时间间隔
        }
        _ofs.write(data, len);
        assert(_ofs.good());
    }

private:
    void createNewFile()
    {
        // 获取时间戳
        time_t t = logs::util::Data::getTime();
        std::stringstream file_name;
        struct tm lt;
        localtime_r(&t, &lt);
        file_name << _file_name;

        // a20041011132416.log
        file_name << lt.tm_year + 1900;
        file_name << lt.tm_mon + 1;
        file_name << lt.tm_mday;
        file_name << lt.tm_hour;
        file_name << lt.tm_min;
        file_name << lt.tm_sec;
        file_name << ".log";
        // 创建文件,自动生成扩展文件名
        // 格式：a.172334554.log
        _ofs.open(file_name.str(), std::ios::app | std::ios::binary);

        assert(_ofs.is_open());
    }

private:
    std::string _file_name;
    std::ofstream _ofs;
    size_t _cur_gap;  // 当前是在第几个时间段
    size_t _gap_size; // 时间段的大小
};

// 错误日志：
// 1.滚动方式写入出错：原因：在写入后没有及时的调整_cur_file_size的大小，以及每次切换文件时都需要将_cur_file_size初始化为0；
// 2.采用模板类时出现报错：原因使用可变参数类模板时，无法将类的模板参数传递给函数；
// 两种解决：1. create<RollBySizeSink， const string&>直接指定，可以解决报错，但并不便捷，没有期望的可变参数函数效果
// 2. 不使用类模板，使用函数模板
// int main()
// {
//     logs::logMsg lm(logs::LogLevel::Value::DEBUG, __LINE__, __FILE__, "日志输出功能测试...", "root");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %n");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S] %m %n");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %n{");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %");
//     // Formatter fmt("abc%%def[%d{%H:%M:%S}] %m %g");
//     // Formatter fmt("abc%%%k%k%gdef[%d{%H:%M:%S}] %m %g");
//     logs::Formatter fmt;
//     std::string res = fmt.format(lm);
//     // LogSink::ptr stdout_lgs = SinkFactory::create<StdoutSink>();
//     // LogSink::ptr file_lgs = SinkFactory::create<FileSink>("./aa/bb/test.log");
//     // LogSink::ptr roll_lgs = SinkFactory::create<RollBySizeSink>("./dd/bb/roll-", 1024*1024);

//     // stdout_lgs->log(res.c_str(), res.size());
//     // file_lgs->log(res.c_str(), res.size());
//     // int size = 0, cnt = 0;
//     // while(size < 1024*1024*5)
//     // {
//     //     std::string tmp = res + std::to_string(cnt++);
//     //     roll_lgs->log(tmp.c_str(), tmp.size());
//     //     size += tmp.size();
//     // }

//     logs::LogSink::ptr time_lgs = logs::SinkFactory::create<RollByTimeSink>("./ee/bb/roll-time-", TimeGap::GAP_SECOND);
//     time_t old = logs::util::Data::getTime();
//     while(logs::util::Data::getTime() < old + 5)
//     {
//         usleep(1000);
//         time_lgs->log(res.c_str(), res.size());
//     }
//     return 0;
// }

// int main()
// {
//     logs::LogSink::ptr stdout_lgs = logs::SinkFactory::create<logs::StdoutSink>();
//     logs::LogSink::ptr file_lgs = logs::SinkFactory::create<logs::FileSink>("./aa/bb/test.log");
//     logs::LogSink::ptr roll_lgs = logs::SinkFactory::create<logs::RollBySizeSink>("./dd/bb/roll-", 1024 * 1024);

//     std::vector<logs::LogSink::ptr> sinks = {stdout_lgs, file_lgs, roll_lgs};
//     logs::Formatter::ptr fmt = std::make_shared<logs::Formatter>();

//     logs::logger::ptr sync_logger = std::make_shared<logs::SyncLogger>("sync_logger", logs::LogLevel::Value::WARN, fmt, sinks);

//     size_t size = 0, cnt = 0;
//     std::string str = "日志器测试... -%d";

//     sync_logger->debug(__FILE__, __LINE__, "%s", "日志器测试...");
//     sync_logger->info(__FILE__, __LINE__, "%s", "日志器测试...");
//     sync_logger->warn(__FILE__, __LINE__, "%s", "日志器测试...");
//     sync_logger->error(__FILE__, __LINE__, "%s", "日志器测试...");
//     sync_logger->fatal(__FILE__, __LINE__, "%s", "日志器测试...");
//     // while (size < 1024 * 1024 * 5)
//     // {
//     //     sync_logger->fatal(__FILE__, __LINE__, "日志器测试-%d", cnt++);
//     //     size += 25;
//     // }

//     return 0;
// }

// 问题一：线程退出时，缓冲区依然有数据的情况，将线程入口函数内部修改成死循环，添加判断条件，当为停止状态，并且缓冲区为空时再退出
// 问题二：在大量的日志输出打印时出现调用纯虚函数的异常，原因：线程创建时采用了分离模式，这样主线程就不会等待任务线程执行结束，
// 但是任务线程需要使用主线程中的数据也就是 _sinks（存放落地方向的列表）
// 主进程退出，数据就会被回收，在调用时就会直接调用LogSink中的log，但是这个接口是纯虚函数，就导致异常退出；
// int main()
// {
//     std::unique_ptr<logs::LoggerBuilder> builder = std::make_unique<logs::localLoggerBuild>();
//     builder->BuilderLoggerType(logs::LoggerType::LOGGER_ASYNC);
//     builder->BuilderLoggerName("async_logger");
//     builder->BuilderLoggerLevel(logs::LogLevel::Value::WARN);
//     builder->BuilderLoggerFormatter("%m%n");
//     builder->buildSink<logs::StdoutSink>();
//     builder->buildSink<logs::FileSink>("./aa/test.log");
//     builder->BuilderEnableUnsafeAsync();
//     logs::logger::ptr logger = builder->build();
//     logger->debug(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->info(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->warn(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->error(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->fatal(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     size_t cnt = 0;
//     while (cnt < 500000)
//     {
//         logger->fatal(__FILE__, __LINE__, "%s - %d", "异步日志器测试...", cnt++);
//     }
//     return 0;
// }

// 缓冲区测试
// int main()
// {
    
//     std::ifstream ifs("./aa/test.log", std::ios::binary);
//     if(!ifs.is_open()) { std::cout << "open file error"; return -1; }
//     // 计算文件数据大小
//     // 知识补充：istream::seekg移动读指针, ostream::seekp移动写指针，这里是读方式打开因此使用seekg；
//     // seekg(偏移量， 基准位置)，偏移量可为正数（向后偏移），可为负数（向前偏移）
//     ifs.seekg(0, std::ios::end); // 将读位置跳转到文件末尾
//     size_t fsize = ifs.tellg(); // 计算当前读指针到起始位置的偏移量
//     ifs.seekg(0, std::ios::beg); // 重新跳转到开始的位置

//     std::string body;
//     body.resize(fsize);
//     ifs.read(&body[0], fsize);
//     if(!ifs.good()) { std::cout << "read file error"; return -2; }
//     std::cout << fsize << std::endl;
//     logs::Buffer buffer;
    
//     buffer.push(body.c_str(), body.size());
//     std::cout << buffer.able_read_size() << std::endl;

//     std::ofstream ofs("./aa/tmp.log", std::ios::binary);
//     if(!ofs.is_open()) { std::cout << "open file error"; return -1; }

//     // ofs.write(buffer.begin(), buffer.able_read_size());
//     size_t sz = buffer.able_read_size();
//     for(int i = 0; i < sz; i++){
//         ofs.write(buffer.begin(), 1);
//         buffer.move_read(1);
//     }
//     ofs.close();
//     ifs.close();
//     return 0;
// }

// 全局日志器管理类测试
// void test_log(){
//     logs::logger::ptr logger = logs::LoggerManager::getInstance().get_Logger("async_logger");
//     logger->debug(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->info(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->warn(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->error(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     logger->fatal(__FILE__, __LINE__, "%s", "异步日志器测试...");
//     size_t cnt = 0;
//     while (cnt < 500000)
//     {
//         logger->fatal(__FILE__, __LINE__, "%s - %d", "异步日志器测试...", cnt++);
//     }
// }
// int main(){
//     std::unique_ptr<logs::LoggerBuilder> builder = std::make_unique<logs::GlobalLoggerBuild>();
//     // builder->BuilderLoggerType(logs::LoggerType::LOGGER_ASYNC);
//     builder->BuilderLoggerName("async_logger");
//     // builder->BuilderLoggerLevel(logs::LogLevel::Value::WARN);
//     // builder->BuilderLoggerFormatter("%m%n");
//     // builder->buildSink<logs::StdoutSink>();
//     // builder->buildSink<logs::FileSink>("./aa/test.log");
//     // builder->BuilderEnableUnsafeAsync();
//     builder->build();
//     test_log();
//     return 0;
// }

void test_log(){
    // logs::logger::ptr logger = logs::LoggerManager::getInstance().get_Logger("async_logger");
    // logs::logger::ptr logger = logs::getLogger("async_logger");
    // logger->debug("%s", "异步日志器测试...");
    // logger->info("%s", "异步日志器测试...");
    // logger->warn("%s", "异步日志器测试...");
    // logger->error("%s", "异步日志器测试...");
    // logger->fatal("%s", "异步日志器测试...");
    // size_t cnt = 0;
    // while (cnt < 500000)
    // {
    //     logger->fatal("%s - %d", "异步日志器测试...", cnt++);
    // }

    DEBUG("%s", "异步日志器测试...");
    INFO("%s", "异步日志器测试...");
    WARN("%s", "异步日志器测试...");
    ERROR("%s", "异步日志器测试...");
    FATAL("%s", "异步日志器测试...");
    size_t cnt = 0;
    while (cnt < 50000)
    {
        FATAL("%s - %d", "异步日志器测试...", cnt++);
    }
}
int main(){
    // 可自定义创建日志器，定义日志器的输出
    // std::unique_ptr<logs::LoggerBuilder> builder = std::make_unique<logs::GlobalLoggerBuild>();
    // builder->BuilderLoggerType(logs::LoggerType::LOGGER_ASYNC);
    // builder->BuilderLoggerName("async_logger");
    // builder->BuilderLoggerLevel(logs::LogLevel::Value::WARN);
    // builder->BuilderLoggerFormatter("%m%n");
    // builder->buildSink<logs::StdoutSink>();
    // builder->buildSink<logs::FileSink>("./aa/test.log");
    // builder->BuilderEnableUnsafeAsync();
    // builder->build();
    test_log();
    return 0;
}